// ----------------------------------------------------------------------------
// atomic_intrinsic.windows.h
// ----------------------------------------------------------------------------
#ifndef FW_ATOMIC_INTRINSIC_WINDOWS_H
#define FW_ATOMIC_INTRINSIC_WINDOWS_H

extern "C" long  __cdecl _InterlockedCompareExchange	( long volatile* a_vpDest, long a_Exchange, long a_Comp );
extern "C" long  __cdecl _InterlockedExchange			( long volatile* a_vpTarget, long a_Value );
extern "C" long  __cdecl _InterlockedExchangeAdd		( long volatile* a_vpAddend, long a_Value );
extern "C" long  __cdecl _InterlockedIncrement			( long volatile* a_vpAddend );
extern "C" long  __cdecl _InterlockedDecrement			( long volatile* a_vpAddend );

#pragma intrinsic (_InterlockedCompareExchange)
#pragma intrinsic (_InterlockedExchange)
#pragma intrinsic (_InterlockedExchangeAdd)
#pragma intrinsic (_InterlockedIncrement)
#pragma intrinsic (_InterlockedDecrement)

#if FW_TARGET_64BIT == 1
extern "C" __int64  __cdecl _InterlockedCompareExchange64	( __int64 volatile* a_vpDest, __int64 a_Exchange, __int64 a_Comp );
extern "C" __int64  __cdecl _InterlockedExchange64			( __int64 volatile* a_vpTarget, __int64 a_Value );
extern "C" __int64  __cdecl _InterlockedExchangeAdd64		( __int64 volatile* a_vpAddend, __int64 a_Value );
extern "C" __int64  __cdecl _InterlockedIncrement64			( __int64 volatile* a_vpAddend );
extern "C" __int64  __cdecl _InterlockedDecrement64			( __int64 volatile* a_vpAddend );

#pragma intrinsic (_InterlockedCompareExchange64)
#pragma intrinsic (_InterlockedExchange64)
#pragma intrinsic (_InterlockedExchangeAdd64)
#pragma intrinsic (_InterlockedIncrement64)
#pragma intrinsic (_InterlockedDecrement64)
#endif // FW_TARGET_64BIT 

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_SET(volatile int32_t* p, int32_t v)
{
	return _InterlockedExchange((volatile long*)p,v);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_GET(volatile int32_t* p)
{
	return _InterlockedExchangeAdd((volatile long*)p,0);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_CAS(volatile int32_t* p, int32_t c, int32_t s)
{
	return _InterlockedCompareExchange((volatile long*)p,s,c);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC(volatile int32_t* p)
{
	return _InterlockedIncrement((volatile long*)p);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC_PREVALUE(volatile int32_t* p)
{
	return _InterlockedExchangeAdd((volatile long*)p,1);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC(volatile int32_t* p)
{
	return _InterlockedDecrement((volatile long*)p);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC_PREVALUE(volatile int32_t* p)
{
	return _InterlockedExchangeAdd((volatile long*)p,-1);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_ADD(volatile int32_t* p, int32_t v)
{
	return _InterlockedExchangeAdd((volatile long*)p,v);
}

#if defined(FW_TARGET_64BIT)
FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_SET64(volatile int64_t* p, int64_t v)
{
	return _InterlockedExchange64((volatile __int64*)p,v);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_GET64(volatile int64_t* p)
{
	return _InterlockedExchangeAdd64((volatile __int64*)p,0);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_CAS64(volatile int64_t* p, int64_t c, int64_t s)
{
	return _InterlockedCompareExchange64((volatile __int64*)p,s,c);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC64(volatile int64_t* p)
{
	return _InterlockedIncrement64((volatile __int64*)p);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC_PREVALUE64(volatile int64_t* p)
{
	return _InterlockedExchangeAdd64((volatile __int64*)p,1);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC64(volatile int64_t* p)
{
	return _InterlockedDecrement64((volatile __int64*)p);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC_PREVALUE64(volatile int64_t* p)
{
	return _InterlockedExchangeAdd64((volatile __int64*)p,-1);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_ADD64(volatile int64_t* p, int64_t v)
{
	return _InterlockedExchangeAdd64((volatile __int64*)p,v);
}

#endif // FW_TARGET_64BIT 

#endif // FW_ATOMIC_INTRINSIC_WINDOWS_H
